<?php
namespace App\Common\Cla\ClaBase;

use App\Common as com;

/*
 * @property nameOfXxx $main
 */
class DataStore extends com\Cla\ClaBase {

	/**
	 * @var array
	 */
	protected array $store = [];

	/**
	 * 已在销毁队列中的通道数量
	 * @var int
	 */
	private int $destructChannelLength = 0;

	/**
	 * 销毁队列通道
	 * @var \Swoole\Coroutine\Channel|null
	 */
	private ?\Swoole\Coroutine\Channel $destructChannel = null;

	public function __construct( array $store = [] ) {
		$this->store = $store;
		//
		parent::__construct();
	}

	/**
	 * 返回自身
	 * @return mixed
	 */
	public function getThis(  ) {
		return $this;
	}

	/**
	 * 检查数据是否存在
	 * @param string $name 数据名
	 * @return bool [false]不存在 [true]存在
	 */
	public function isset( string $name ):bool {
		return isset( $this->store[ $name ] );
	}

	/**
	 * 获取状态
	 * @param string $name 数据名
	 * @return mixed
	 */
	public function __get( string $name ) {
		if( ! $this->isset( $name ) ){
			throw com\Lib\Err\Exception::makeOfNew( 'dataStore中不存在' . $name, com\Lib\Err\Code::$sysDataError );
		}
		//
		if( $this->store[ $name ] instanceof \Closure ){
			return $this->store[ $name ] = $this->store[ $name ]();
		}else{
			// 弱引用
			if( $this->store[ $name ] instanceof \WeakReference ){
				if( $this->store[ $name ]->get() === null ){
					throw com\Lib\Err\Exception::makeOfNew( "引用对象({$name})已被gc，请检查调用方式是否存在问题", com\Lib\Err\Code::$sysAssertError );
				}
				return $this->store[ $name ]->get();
			}
			//
			return $this->store[ $name ];
		}
	}

	/**
	 * 设置状态
	 * @param string $name 数据名
	 * @param mixed $value 支持回调函数（一次调用，返回值将覆盖$name）
	 * @return void
	 */
	public function __set( string $name, $value ) {
		$this->set( $name, $value );
	}

	/**
	 * 继承旧数据创建新分支
	 * @return $this
	 */
	public function fork() {
		$className = get_called_class();
		//
		$store = [];
		foreach( $this->store as $storeKey => $storeValue ){
			$store[ $storeKey ] = $storeValue;
		}
		//
		return new $className( $store );
	}

	/**
	 * 继承旧数据创建新分支(使用硬引用)
	 * @return $this
	 */
	public function forkEntity() {
		$className = get_called_class();
		//
		$store = [];
		foreach( $this->store as $storeKey => $storeValue ){
			if( $storeValue instanceof \WeakReference ){
				$store[ $storeKey ] = $storeValue->get();
			}else{
				$store[ $storeKey ] = $storeValue;
			}
		}
		//
		return new $className( $store );
	}

	/**
	 * @param string $name 数据名
	 * @param mixed $value 值
	 * @return bool
	 */
	public function set( string $name, $value ):bool {
		if( is_object( $value ) ){
			// $this->store[ $name ] = $value;
			$this->store[ $name ] = \WeakReference::create( $value ); // 使用弱引用，防止引用阻止销毁;
		}else{
			$this->store[ $name ] = $value;
		}
		//
		return true;
	}

	/**
	 * 如果不存在则设置
	 * @param string $name 数据名
	 * @param mixed $value 值
	 * @return bool|null [true]只有true [null]
	 */
	public function setNx( string $name, $value ):?bool {
		if( ! $this->isset( $name ) ){
			return $this->set( $name, $value );
		}
		//
		return null;
	}

	/**
	 * 如果不存在则设置
	 * @param mixed $value 值
	 * @return bool|null [true]只有true [null]
	 */
	public function setNxOfMain( $value ):?bool {
		return $this->setNx( 'main', $value );
	}

	/*
	public function forkOfEntity(  ) {
		$newDataStore = $this->fork();
		$newDataStore->storeWeakReferenceToEntity();
		//
		return $newDataStore;
	}

	public function storeWeakReferenceToEntity(  ):void {
		foreach( $this->store as &$storeValue ){
			// 弱引用
			if( $storeValue instanceof \WeakReference ){
				$storeValue = $storeValue->get();
			} unset( $storeValue );
		}
	}
	*/

	/**
	 * 申请
	 */
	public function apply(  ) {
		// ...
/*		if( $this->destructChannel === null ){
			$this->destructChannel = new \Swoole\Coroutine\Channel();
			$that = $this;
			go( function() use ( $that ){
				while( true ){
					$that->destructChannel->pop();
					$that->destructChannelLength--;
					if( $this->destructChannelLength === 0 ){
						// 重置
						$that->destructChannel = null;
						$that->destructChannelLength = 0;
						//
						break;
					}
				}
			} );
		}
		//
		$this->destructChannelLength++;*/
		//
		return $this;
	}

	/**
	 * 释放
	 */
	public function release(  ) {
		if( $this->destructChannel === null ){
			// throw com\Lib\Err\Exception::makeOfNew( '销毁通道不存在', com\Lib\Err\Code::$sysAssertError );
			return;
		}
		$this->destructChannel->push( true );
		//
	}

	// ===============================
	//
	//
	// 下面为静态方法
	//
	//
	// ===============================

	public static function newOfThis( $_this ) {
		$dataStore = new static();
		$dataStore->main = $_this;
		return $dataStore;
	}
	
}
